﻿/* 
   ***** ***** ***** ***** ***** ***** 
   ***** 
   *****  Date
   ***** 
   ***** ***** ***** ***** ***** ***** 
*/


/*    toISOString - support for IE    */
if (!Date.prototype.toISOString) {

    (function () {

        function pad(number) {
            var r = String(number);
            if (r.length === 1) {
                r = '0' + r;
            }
            return r;
        }

        Date.prototype.toISOString = function () {
            return this.getUTCFullYear()
                + '-' + pad(this.getUTCMonth() + 1)
                + '-' + pad(this.getUTCDate())
                + 'T' + pad(this.getUTCHours())
                + ':' + pad(this.getUTCMinutes())
                + ':' + pad(this.getUTCSeconds())
                + '.' + String((this.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5)
                + 'Z';
        };

    } ());
}

/*    parse - supports for IE   */
(function (Date, undefined) {
    var origParse = Date.parse, numericKeys = [1, 4, 5, 6, 7, 10, 11];
    Date.parse = function (date) {
        var timestamp, struct, minutesOffset = 0;

        // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string
        // before falling back to any implementation-specific date parsing, so that’s what we do, even if native
        // implementations could be faster
        //              1 YYYY                2 MM       3 DD           4 HH    5 mm       6 ss        7 msec        8 Z 9 ±    10 tzHH    11 tzmm
        //ORIGINAL    /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date)
        if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3,}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) {
            // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC
            for (var i = 0, k; (k = numericKeys[i]); ++i) {
                struct[k] = +struct[k] || 0;
            }

            // allow undefined days and months
            struct[2] = (+struct[2] || 1) - 1;
            struct[3] = +struct[3] || 1;

            if (struct[8] !== 'Z' && struct[9] !== undefined) {
                minutesOffset = struct[10] * 60 + struct[11];

                if (struct[9] === '+') {
                    minutesOffset = 0 - minutesOffset;
                }
            }

            // ms structure could be max 3 decimal places
            var milliseconds = (struct[7] + "").length;
            if ( milliseconds > 3) {
                milliseconds = Math.round(struct[7] / Math.pow(10, milliseconds - 3));
            }
            else {
                milliseconds = struct[7];
            }

            timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], milliseconds);
        }
        else {
            timestamp = origParse ? origParse(date) : NaN;
        }

        return timestamp;
    };
} (Date));



/* 
   ***** ***** ***** ***** ***** ***** 
   ***** 
   *****  Array
   ***** 
   ***** ***** ***** ***** ***** ***** 
*/

/*    take - take first COUNT elements of array  */
Array.prototype.take = function(count) {
    return this.slice(0, count);
};

/*    skip - skips first COUNT elements of array   */
Array.prototype.skip = function(count) {
    return this.slice(count, this.length);
};

/*    takeUpToMaxOrMin - when there is more than Max elements, then min is returned,
                         otherwise min elements is returned
*/
Array.prototype.takeUpToMaxOrMin = function (minCount, maxCount) {
    if (this.length > maxCount) {
        return this.take(minCount);
    }
    return this.take(maxCount);
};